/**
 * 
 */
package org.hsqldb;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.jdbclib.JdbcConnectionPool;
import org.hsqldb.persist.HsqlProperties;

/**
 * Subclass of Table to handle jdbc data source.
 * <p>
 * 
 * @author flashwei@gmail.com(wei)
 * @version
 * 
 */
public class JdbcTable extends Table {

	private String realTableName = "";

	private String realSchemaName = "";

	private String realUser = "";

	private String realPass = "";

	private String dataSource = "";

	private String driverClass = "";

	private String jdbcURL = "";

	private String where = "";

	JdbcTable(Database db, HsqlName name, int type) throws HsqlException {
		super(db, name, type);
	}

	/**
	 * High level command to assign a data source to the table definition.
	 * Reassigns only if the data source or direction has changed.
	 * 
	 * @param dataSourceNew
	 *            is like
	 *            <code>jdbc:derby:test;class=org.jdbc.xxxx;schema=s1;table=t1;user=u1;pass=p1</code>
	 */
	protected void setDataSource(Session session, String dataSourceNew,
			boolean isReversedNew, boolean newFile) throws HsqlException {
		dataSourceNew = dataSourceNew.trim();
		HsqlProperties tableprops = HsqlProperties.delimitedArgPairsToProps(
				dataSourceNew, "=", ";", null);

		switch (tableprops.getErrorKeys().length) {

		case 0:
			throw Trace.error(Trace.TEXT_TABLE_SOURCE,
					Trace.TEXT_TABLE_SOURCE_FILENAME);
		case 1:

			// source file name is the only key without a value
			jdbcURL = tableprops.getErrorKeys()[0].trim();
			break;

		default:
			throw Trace.error(Trace.TEXT_TABLE_SOURCE,
					Trace.TEXT_TABLE_SOURCE_VALUE_MISSING, tableprops
							.getErrorKeys()[1]);
		}

		realSchemaName = tableprops.getProperty("schema");
		realTableName = tableprops.getProperty("table");
		realUser = tableprops.getProperty("user");
		realPass = tableprops.getProperty("pass");
		driverClass = tableprops.getProperty("class");
		where = tableprops.getProperty("where");

		connect(session);
	}

	private void insertDataFromJdbc(Connection connection, Session session)
			throws HsqlException {
		Statement stat = null;
		ResultSet rs = null;
		ResultSetMetaData metadata = null;
		String sql = "select * from " + realSchemaName + "." + realTableName
				+ (where == null ? "" : where);
		try {
			stat = connection.createStatement();
			rs = stat.executeQuery(sql);
			metadata = rs.getMetaData();
			int colCount = metadata.getColumnCount();
			//init the table structure
			initTableStruct(metadata, colCount);
			
			while (rs.next()) {
				Object[] data = new Object[colCount];
				// Retrieve the data from resultset
				for (int i = 0; i < colCount; i++) {
					data[i] = rs.getObject(i + 1);
				}
				
				//insert data into table;
				insert(session, data);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (stat != null)
					stat.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	private void initTableStruct(ResultSetMetaData metadata, int count)
			throws HsqlException {
		addColumns(metadata, count);
		createPrimaryKey(null, null, true);
	}

	public void connect(Session session) throws HsqlException {

		Connection connection = null;

		connection = JdbcConnectionPool.getInstance().getConnection(
				driverClass, jdbcURL, realUser, realPass);

		if (connection == null)
			throw Trace.error(Trace.CANNOT_CONNECT_TABLE);
		try {
			insertDataFromJdbc(connection, session);
		} finally {
			if (connection != null)
				JdbcConnectionPool.close(connection);
		}
	}

	/**
	 * This method does some of the work involved with managing the creation and
	 * openning of the cache, the rest is done in Log.java and TextCache.java.
	 * 
	 * Better clarification of the role of the methods is needed.
	 */
	private void openCache(Session session, String dataSourceNew,
			boolean isReversedNew, boolean isReadOnlyNew) throws HsqlException {

		if (dataSourceNew == null) {
			dataSourceNew = "";
		}

		disconnect(session);

		dataSource = dataSourceNew;

		// connect(session, isReadOnlyNew);
	}
}
